package com.javalong.mir.common.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.xml.bind.annotation.XmlElement;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sword.lang.HttpUtils;
import org.sword.wechat4j.common.Config;
import org.sword.wechat4j.message.TemplateMsg;
import org.sword.wechat4j.message.template.TemplateMsgBody;
import org.sword.wechat4j.message.template.TemplateMsgData;
import org.sword.wechat4j.token.TokenProxy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.javalong.mir.bean.JsApiTicket;
import com.javalong.mir.bean.MyX509TrustManager;
import com.javalong.mir.bean.TemplatMsgObject;
import com.javalong.mir.bean.TemplateMsgType;
import com.javalong.mir.bean.WechatOpenId;

/**
 * 操作微信提供的各种接口
 * 
 * @author 郭昊
 * 
 */
public class WechatUtil {
	/**
	 * 微信的appID
	 */
	private static final String appId = "wxf58f3a4397ee01dc";
	/**
	 * 微信的 AppSecret
	 */
	private static final String appSecret = "d0473f59c2fc2f7ca28fc8ec38a8cc1f";

	private static final Logger logger = LoggerFactory
			.getLogger("wechat");

	/**
	 * get方法
	 * 
	 * @param url
	 * @return
	 * @throws HttpException
	 * @throws IOException
	 */
	private static String get(final String url) throws HttpException,
			IOException {
		String result = null;
		HttpClient client = new HttpClient();
		GetMethod getMethod = new GetMethod(url);
		int statusCode = client.executeMethod(getMethod);
		if (statusCode == 200) {
			String str = getMethod.getResponseBodyAsString();
			result = new String(str.getBytes("iso8859-1"), "utf-8");
		} else {
			result = "error:" + statusCode;
		}

		return result;

	}

	/**
	 * 获取用户openid 列表
	 * 
	 * @throws IOException
	 * @throws HttpException
	 */

	public static void listOpenId() throws HttpException, IOException {
		/*
		 * 如果accessToken 不存在，获取accessToken
		 */
		String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="
				+ accessToken();

		System.out.println(get(url));
	}

	/**
	 * 获取accessToken
	 * 
	 * @throws IOException
	 * @throws HttpException
	 */
	public static String accessToken()  {
		return TokenProxy.accessToken();
		
	}

	/**
	 * 获取JSApiTicket
	 * @author Junyan2015
	 * @date 2016年2月16日 上午9:36:52
	 * @return
	 * @throws HttpException
	 * @throws IOException
	 */
	public static String jsapiTicket() throws HttpException, IOException {
		String accessToken = accessToken();
		String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?"
				+ "access_token="+accessToken+"&type=jsapi";
		String result = get(url);
		JsApiTicket ticket = JSON.parseObject(result, JsApiTicket.class);
		return ticket.getTicket();
	}
	
	/**
	 * 获取openid
	 * 
	 * @throws IOException
	 * @throws HttpException
	 */
	public static WechatOpenId getOpenid(final String code){

		WechatOpenId wechatOpenId = null;
		try {
			String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
					+ appId + "&secret=" + appSecret + "&code=" + code
					+ "&grant_type=authorization_code";
			String result = get(url);
			logger.info(result);
			wechatOpenId = JSON.parseObject(result, WechatOpenId.class);
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return wechatOpenId;

	}
	
	/**
	 * 获取微信图片url
	 * @author Junyan2015
	 * @date 2016年4月18日 上午11:06:13
	 * @since
	 */
	public static String fetchImg(String mediaId) {
		String from = null;
	
			from = "http://file.api.weixin.qq.com/cgi-bin/media/get?"
					+ "access_token="+accessToken()
							+ "&media_id="+mediaId;
	
		
		return from;
		
	}

	/**
	 * 修改自定义的菜单
	 * 
	 * @throws IOException
	 * @throws HttpException
	 */

	public static boolean setMenu(final String body) throws HttpException,
			IOException {
		String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="
				+ accessToken();
		httpRequest(url, "POST", body);
		return false;
	}

	/**
	 * 获取用户的信息
	 * 
	 * @throws IOException
	 * @throws HttpException
	 */
	public static String getWechatUser(final String openId){
		
			String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken()+"&openid="+openId+"&lang=zh_CN";
			String result = httpRequest(url, "GET",null).toString();
			return result;
		
	}

	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static JSONObject httpRequest(final String requestUrl,
			final String requestMethod, final String outputStr) {
		JSONObject jsonObject = null;
		StringBuffer buffer = new StringBuffer();
		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
					.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod))
				httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(
					inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			System.out.println(buffer.toString());
		   jsonObject =  JSON.parseObject(buffer.toString());
		} catch (ConnectException ce) {
			ce.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return jsonObject;
	}

	public static String getAppid() {
		return appId;
	}

	public static String getAppsecret() {
		return appSecret;
	}

	
	
	/**
	 * 根据code值获取微信openid的相关信息
	 * @author Junyan2015
	 * @date 2016年4月18日 上午11:07:53
	 * @since
	 */
	public static String getWechatUserByCode(String code) {
		try {
			WechatOpenId wechatOpenId = getOpenid(code);
			System.out.println(JSON.toJSONString(wechatOpenId));
			String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+wechatOpenId.getAccess_token()+"&openid="+wechatOpenId.getOpenid()+"&lang=zh_CN";
			System.out.println(url);
			String result = get(url);
			return result;
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 根据openid获取用户基本信息
	 * @author Junyan2015
	 * @date 2016年4月18日 上午11:15:54
	 * @since
	 */
	public static String getWechatUserByWechatOpenId(WechatOpenId wechatOpenId) {
		try {
			System.out.println(JSON.toJSONString(wechatOpenId));
			String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+wechatOpenId.getAccess_token()+"&openid="+wechatOpenId.getOpenid()+"&lang=zh_CN";
			System.out.println(url);
			String result = get(url);
			return result;
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 发送微信模板消息
	 * @author Junyan2015
	 * @date 2016年4月18日 上午11:08:51
	 * @param toUserOpenId 用户的openid,可从Base类中的getWechatOpenId()获取
	 * @param detailUrl 详请跳转链接,如不需要可不填写
	 * @param templateId 在TemplateMsgType类中
	 * @param data 构造模板消息内容
	 * @since
	 */
	@SuppressWarnings("rawtypes")
	public static String sendTemplateMsg(String toUserOpenId, String detailUrl, String templateId, TemplatMsgObject data) {
		TemplateMsg msg = new TemplateMsg();
		TemplateMsgBody body = new TemplateMsgBody();
		body.setTemplateId(templateId);
		body.setTouser(toUserOpenId);
		body.setUrl(detailUrl);
		body.setTopcolor("#173177");
		List<TemplateMsgData> list = new ArrayList<TemplateMsgData>();
		Iterator iterator = data.entrySet().iterator();
		while(iterator.hasNext()) {
			Entry entry = (Entry) iterator.next();
			String name = (String) entry.getKey();
			String value = (String) entry.getValue();
			TemplateMsgData templateMsgData = new TemplateMsgData();
			if(name.equals("remark")) {
				templateMsgData.setColor("#173177");
				if(templateId.equals(TemplateMsgType.PAY_SUCCESS)) {
					name = "Remark";
				}
			}
			if(name.equals("first")) templateMsgData.setColor("#173177");
			templateMsgData.setName(name);
			templateMsgData.setValue(value);
			list.add(templateMsgData);
		}
		
		body.setData(list);
		String msgId = msg.send(body);
		if(msgId != null) {
			logger.info("消息发送成功！wechat发送消息ID为"+msgId);
		}else {
			logger.info("消息发送失败!");
		}
		return msgId;
	} 
	
	
    /**
     * 支付签名算法
     * @author Junyan2015
     * @date 2016年4月20日 下午2:20:36
     * @since
     */
    public static String signature(Object object) {
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = object.getClass().getDeclaredFields();
        // 请求参数按英文字典序排序签名
        Arrays.sort(fields, new Comparator<Field>() {
            public int compare(Field o1, Field o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        for (Field field : fields) {
            // sign不参与签名
            if ("sign".equals(field.getName())) {
                continue;
            }
            XmlElement xmlElement = field.getAnnotation(XmlElement.class);
            if (xmlElement == null) {
                try {
                    Method getMethod = object.getClass().getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
                    xmlElement = getMethod.getAnnotation(XmlElement.class);
                } catch (NoSuchMethodException e) {
                    logger.warn("get method not found : " + field.getName());
                }
            }
            field.setAccessible(true);
            try {
                map.put(xmlElement != null ? xmlElement.name() : field.getName(), field.get(object));
            } catch (IllegalAccessException e) {
            }
        }
        return signature(map);
    }
    
    /**
     * 支付签名算法map
     * @author Junyan2015
     * @date 2016年4月20日 下午2:33:02
     * @since
     */
    public static String signature(Map<String, Object> map) {
        map.put("sign", ""); // sign不参与签名
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != null && !"".equals(entry.getValue())) {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder signatureTemp = new StringBuilder();
        for (int i = 0; i < size; i++) {
            signatureTemp.append(arrayToSort[i]);
        }
        signatureTemp.append("key=").append(Config.instance().getMchKey());
        String signatureSource = signatureTemp.toString();
        logger.debug("sign source : " + signatureSource);
        String signature = DigestUtils.md5Hex(signatureSource).toUpperCase();
        logger.debug("sign result : " + signature);
        return signature;
    }

    
    /**
     * 上传文章中的图片资源
     * @param instream
     * @return
     */
    public static String uploadArticleImage(File file){
    	String url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token="
				+ accessToken();
    	return HttpUtils.postFile(url,file.getName(), file);
    }
    
    /**
     * 上传app中的图片资源
     * @param file
     * @return
     */
    public static String uploadImageMedia(File file){
    	String url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token="
				+ accessToken()+"&type=image";
    	return HttpUtils.postFile(url,file.getName(), file);
    }
    
    /**
     * 上传图文消息
     * @param instream
     * @return
     */
    public static String uploadArticles(String articles){
    	String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token="
				+ accessToken();
    	return HttpUtils.post(url, articles);
    }
	
    
    /**
     * 推送消息
     * @param messageData
     * @return
     */
    public static String pushMessage(String messageData){
    	String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token="
				+ accessToken();
    	return HttpUtils.post(url, messageData);
    }
    
    
    /**
     * 根据msgId 删除文章
     * @param msgId
     * @return
     */
    public static String delete(String msgId){
    	String url = "https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token="
				+ accessToken();
    	return HttpUtils.post(url, msgId);
    }
    
    
    /**
     * 创建组
     * @param data
     * @return
     */
    public static String createGroup(String data) {
    	String url = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token="
				+ accessToken();
    	return HttpUtils.post(url, data);
	}
    
    /**
     * 移动用户至某个组
     * @param data
     * @return
     */
    public static String moveUserToGroup(String data) {
    	String url = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token="
				+ accessToken();
    	return HttpUtils.post(url, data);
	}
    
    
    /**
     * 创建菜单
     * @param data
     * @return
     */
    public static String createMenu(String data){
    	String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+ accessToken();
    	return HttpUtils.post(url, data);
    }
    
 
    /**
     * 客服接口
     * @param data
     * @return
     */
    public static String sendCustomMessage(String data){
    	String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+accessToken();
    	return HttpUtils.post(url, data);
    }
    
	public static void main(String[] args) throws Exception {
	
		System.out.println(getWechatUser("okLH0ssHGf7HkGe9npqwcyubI1ro"));
		//System.out.println(JSON.toJSONString(getOpenid("021fd4fd75369d00247ddbc07a84e50I")));
	}

}
